package com.alibaba.service;

import com.alibaba.common.ResponseResult;
import com.alibaba.define.domain.UserDO;
import com.alibaba.define.domain.vo.BlogUserLoginVO;
import com.alibaba.define.domain.vo.UserInfoVO;
import com.alibaba.define.service.UserService;
import com.alibaba.define.service.request.RegisterRequest;
import com.alibaba.define.service.request.UpdateUserRequest;
import com.alibaba.domain.LoginUser;
import com.alibaba.fastjson.JSON;
import com.alibaba.manager.UserManager;
import com.alibaba.utils.BeanCopyUtils;
import com.alibaba.utils.JwtUtil;
import com.alibaba.utils.RedisCache;
import com.alibaba.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

import static com.alibaba.common.SystemConstants.*;
import static com.alibaba.define.enums.AppHttpCodeEnum.*;
import static com.alibaba.define.enums.AppHttpCodeEnum.SYSTEM_EXECUTE_ERROR;

/**
 * @author : hanyang
 * @date : 2023-11-03 09:11
 **/

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    AuthenticationManager authenticationManager;

    @Resource
    RedisCache redisCache;

    @Resource
    UserManager userManager;

    @Resource
    PasswordEncoder passwordEncoder;

    @Override
    public ResponseResult<BlogUserLoginVO> login(UserDO userDO) {

        log.info("UserServiceImpl#login() request:{}", JSON.toJSONString(userDO));
        if (StringUtils.isEmpty(userDO.getUserName()) || StringUtils.isEmpty(userDO.getPassword())) {
            return ResponseResult.error(REQUIRE_USERNAME.getCode(), REQUIRE_USERNAME.getMsg());
        }
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDO.getUserName(), userDO.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        // 判断是否认证通过
        if (Objects.isNull(authenticate)) {
            return ResponseResult.error(LOGIN_ERROR.getCode(), LOGIN_ERROR.getMsg());
        }
        // 获取userId生成token
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        Long userId = loginUser.getUser().getId();
        String jwt = JwtUtil.createJWT(String.valueOf(userId));
        // 把用户信息存入redis
        redisCache.setCacheObject(REDIS_KEY_PREFIX + userId, loginUser);
        // DO => VO
        UserInfoVO userInfoVO = BeanCopyUtils.copyBean(loginUser.getUser(), UserInfoVO.class);
        // 把token和用户信息封装返回
        BlogUserLoginVO blogUserLoginVO = new BlogUserLoginVO();
        blogUserLoginVO.setToken(jwt)
                .setUserInfo(userInfoVO);
        return ResponseResult.ok(blogUserLoginVO);
    }

    @Override
    public ResponseResult<Void> logout() {

        log.info("UserServiceImpl#logout()...");
        // 获取userId
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser)authentication.getPrincipal();
        Long id = loginUser.getUser().getId();
        // 删除redis里的用户信息
        redisCache.deleteObject(REDIS_KEY_PREFIX + id);
        return ResponseResult.ok();
    }

    @Override
    public ResponseResult<UserInfoVO> getUserInfo() {

        log.info("UserServiceImpl#getUserInfo()...");
        try {
            Long userId = SecurityUtils.getUserId();
            // 这里要去查询数据库
            UserDO userDO = userManager.selectUserById(userId);
            UserInfoVO userInfoVO = BeanCopyUtils.copyBean(userDO, UserInfoVO.class);
            return ResponseResult.ok(userInfoVO);
        } catch (Exception e) {
            log.error("UserServiceImpl ==> getUserInfo Exception:{}", JSON.toJSONString(e));
        }
        return ResponseResult.error(SYSTEM_EXECUTE_ERROR.getCode(), SYSTEM_EXECUTE_ERROR.getMsg());
    }

    @Override
    public ResponseResult<Void> updateUserInfo(UpdateUserRequest request) {
        log.info("UserServiceImpl ==> getUserInfo request:{}", JSON.toJSONString(request));
        try {
            // 参数校验
            if (!this.checkUpdateUserInfoRequest(request)) {
                log.error("UserServiceImpl ==> updateUserInfo checkUpdateUserInfoRequest error request:{}", JSON.toJSONString(request));
                return ResponseResult.error(WRONG_PARAMETER.getCode(), WRONG_PARAMETER.getMsg());
            }
            UserDO userDO = BeanCopyUtils.copyBean(request, UserDO.class);
            if (userManager.updateUserInfo(userDO)) {
                return ResponseResult.ok();
            }
            return ResponseResult.error(UPDATE_FAILED.getCode(), UPDATE_FAILED.getMsg());
        } catch (Exception e) {
            log.error("UserServiceImpl ==> updateUserInfo Exception:{}", JSON.toJSONString(e));
        }
        return ResponseResult.error(SYSTEM_EXECUTE_ERROR.getCode(), SYSTEM_EXECUTE_ERROR.getMsg());
    }

    @Override
    public ResponseResult<Void> register(RegisterRequest request) {
        log.info("UserServiceImpl ==> register() request:{}", JSON.toJSONString(request));
        try {
            if (!this.checkRegisterRequest(request)) {
                log.error("UserServiceImpl ==> register checkUpdateUserInfoRequest error request:{}", JSON.toJSONString(request));
                return ResponseResult.error(WRONG_PARAMETER.getCode(), WRONG_PARAMETER.getMsg());
            }

            // 校验用户名是否存在
            if (userManager.isUsernameExist(request.getUserName())) {
                log.info("UserServiceImpl ==> register userName:{} is already exist!", request.getUserName());
                return ResponseResult.error(USERNAME_EXIST.getCode(), USERNAME_EXIST.getMsg());
            }

            // 校验邮箱是否存在
            if (userManager.isEmailExist(request.getEmail())) {
                log.info("UserServiceImpl ==> register email:{} is already exist!", request.getEmail());
                return ResponseResult.error(EMAIL_EXIST.getCode(), EMAIL_EXIST.getMsg());
            }

            // request => userDO
            UserDO userDO = this.buildUserDOByRegisterRequest(request);
            if (userManager.userRegister(userDO)) {
                return ResponseResult.ok();
            }
            return ResponseResult.error(REGISTER_FAILED.getCode(), REGISTER_FAILED.getMsg());

        } catch (Exception e) {
            log.error("UserServiceImpl ==> register Exception:{}", JSON.toJSONString(e));
        }
        return ResponseResult.error(SYSTEM_EXECUTE_ERROR.getCode(), SYSTEM_EXECUTE_ERROR.getMsg());
    }

    private UserDO buildUserDOByRegisterRequest(RegisterRequest request) {
        UserDO userDO = BeanCopyUtils.copyBean(request, UserDO.class);
        // 密码转换
        userDO.setPassword(passwordEncoder.encode(request.getPassword()));
        userDO.setType(GENERAL_USER);
        userDO.setStatus(AVAILABLE);
        // 设置默认头像
        userDO.setAvatar(DEFAULT_AVATAR);
        return userDO;
    }

    private boolean checkUpdateUserInfoRequest(UpdateUserRequest request) {
        if (Objects.isNull(request)) {
            return false;
        }
        return request.getId() != null && request.getEmail() != null && request.getAvatar() != null && request.getNickName() != null && request.getSex() != null;
    }

    private boolean checkRegisterRequest(RegisterRequest request) {
        if (Objects.isNull(request)) {
            return false;
        }
        return request.getEmail() != null && request.getUserName() != null && request.getNickName() != null && request.getPassword() != null;
    }
}
